import json
import pathlib
import urllib.request as request


# 词典正文编码
body_encoding = 'utf-8'

# 词典正文本地缓存路径后缀
body_save_end = '.md'

# 词典正文本地缓存路径前缀
body_save_lead = 'dict/'

# 词典任一文档中表示正文的字段
doc_body_key = 'body'

# 路径。用于获取正文。通常是章节范围
doc_primary_key = 'slug'

# 最近发布时间。若有新发布，读取对应正文
doc_version_key = 'published_at'

# 词典全部文档接口
docs_api = 'repos/zgyxfz/dict/docs/'

# 语雀接口基本路径
endpoint_yuque = 'https://yuque.com/api/v2/'

# 词典有用元信息文件
meta_file = '.dict_meta.json'

# 语雀认证字串文件
token_file = 'yuque_token.txt'

# 语雀要求，不必管它
user_agent = '@yuque/sdk'


# 正文缓存文件对象
body_save = lambda i: pathlib.Path(f'{body_save_lead}{i}{body_save_end}')

# 语雀认证字串，由语雀生成、本应用用户提供
with open(token_file) as f: token_yuque = f.read()


def fetch_new_body(meta_new, meta_old):
    '''根据词典元信息从词典服务器同步正文本地缓存。

        参数：
            meta_new - 来自词典服务器的词典元信息
            meta_old - 词典元信息本地缓存
    '''

    # 若词典正文本地缓存目录不存在，创建它
    body_dir = pathlib.Path(body_save_lead)
    body_dir.is_dir() or body_dir.mkdir()
    
    for doc_new in meta_new:
        for doc in meta_old:
            if doc == doc_new:  # 此正文已同步，无需发起请求
                break
        else:
            # 从服务器获取词典中该文档的正文
            doc_id = doc_new[doc_primary_key]
            body = fetch_yuque(docs_api + doc_id)[doc_body_key]
            body_save(doc_id).write_text(body, body_encoding)


def fetch_yuque(api):
    '''向词典服务器发起一个请求。

        参数及返回：
            api                 return
            docs_api            词典元信息
            docs_api doc_id     词典某文档
    '''
    
    # 语雀要求请求头，不必管它
    headers = {'User-Agent': user_agent, 'X-Auth-Token': token_yuque}
    
    req = request.Request(f'{endpoint_yuque}{api}', headers=headers)
    with request.urlopen(req) as f: response = f.read()
    return json.loads(response)['data']


def update_meta_cache(meta_new):
    '''更新词典有用元信息本地缓存。

        参数：
            meta_new - 新缓存
        返回：
            meta_old - 旧缓存
    '''
    try:
        with open(meta_file) as f: meta_old = json.load(f)
    except:  # 本地缓存不存在，创建它
        meta_old = {}
    with open(meta_file, 'w') as f:        
        json.dump(meta_new, f, separators=(',',':'))  # 节约磁盘空间
    return meta_old


def update_body():
    '''从服务器同步词典全部正文本地缓存。
    '''
    
    docs = fetch_yuque(docs_api)  # 从词典服务器获取DocSerializer[]
    keys = doc_primary_key, doc_version_key
    
    meta_new =  [{k: d[k] for k in d if k in keys} for d in docs]
    
    meta_old = update_meta_cache(meta_new)
    
    remove_old_body(meta_new, meta_old)
    fetch_new_body(meta_new, meta_old)


def remove_old_body(meta_new, meta_old):
    '''删除过时的词典正文本地缓存。

        参数：
            meta_new - 来自词典服务器的词典元信息
            meta_old - 词典元信息本地缓存
    '''
    docs_id_new = [doc_new[doc_primary_key] for doc_new in meta_new]
    for doc_old in meta_old:
        doc_id_old = doc_old[doc_primary_key]
        if doc_id_old not in docs_id_new:
            body_save(doc_id_old).unlink()

